package com.leadingsoft.pwxk.sync;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javax.persistence.EntityManager;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.leadingsoft.plat.converter.DepartmentConverter;
import com.leadingsoft.plat.converter.UserConverter;
import com.leadingsoft.plat.dto.DepartmentDto;
import com.leadingsoft.plat.dto.DepartmentShortDto;
import com.leadingsoft.plat.dto.RoleDto;
import com.leadingsoft.plat.dto.UserDto;
import com.leadingsoft.plat.model.Department;
import com.leadingsoft.plat.model.QDepartment;
import com.leadingsoft.plat.model.QRole;
import com.leadingsoft.plat.model.Role;
import com.leadingsoft.plat.model.User;
import com.leadingsoft.plat.model.Department.Type;
import com.leadingsoft.plat.repository.DepartmentRepository;
import com.leadingsoft.plat.repository.RoleRepository;
import com.leadingsoft.plat.repository.UserRepository;
import com.leadingsoft.plat.services.DepartmentService;
import com.leadingsoft.plat.services.UserService;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.impl.JPAQuery;

import lombok.extern.slf4j.Slf4j;

/**
 * Created by zh on 2015/12/16.
 */
@Slf4j
@Service
public class SyncDepartmentUserServiceImpl implements BaseSyncService {

	@Autowired
	private SyncProperties syncProperties;
	@Autowired
	private RestTemplate restTemplate;
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private DepartmentService departmentService;
	@Autowired
	private DepartmentRepository departmentRepository;
	@Autowired
	private EntityManager em;
	@Autowired
	private UserService userService;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private UserConverter userConverter;
	@Autowired
	private DepartmentConverter departmentConverter;
	@Autowired
	private RoleRepository roleRepositoryl;
	private final QDepartment qDepartment = QDepartment.department;

	@Transactional
	/*@Scheduled(cron = "#{sync['cron']}")*/
	public void syncDepartment() {

		// 任务是否启动
		if (!syncProperties.getStart()) {
			log.info("<---------sync department not need start----------->");
			return;
		}
		long start = System.currentTimeMillis();
		log.info("<---------sync department start----------->");

		try {
			// 部门信息
			log.info(syncProperties.getDepartmentUrl());
			String resultStr = restTemplate.getForObject(
					syncProperties.getDepartmentUrl() + "?fromUpdatedDate={fromUpdatedDate}", String.class,
					syncProperties.getFromUpdatedDate());
			List<DepartmentInfo> departmentInfos = objectMapper.readValue(resultStr,
					new TypeReference<List<DepartmentInfo>>() {
					});
			log.info("sync department count is " + departmentInfos.size());
			// 用户
			String userStrs = restTemplate.getForObject(
					syncProperties.getUserUrl() + "?fromUpdatedDate={fromUpdatedDate}", String.class,
					syncProperties.getFromUpdatedDate());
			List<UserInfo> userNewInfos = objectMapper.readValue(userStrs, new TypeReference<List<UserInfo>>() {
			});
			log.info("sync user count is " + userNewInfos.size());

			// 用户部门关系
			String relations = restTemplate.getForObject(
					syncProperties.getUserDepartmentUrl() + "?fromUpdatedDate={fromUpdatedDate}", String.class,
					syncProperties.getFromUpdatedDate());
			List<UserDepartment> userDepartments = objectMapper.readValue(relations,
					new TypeReference<List<UserDepartment>>() {
					});

			// 处理
			process(departmentInfos, userNewInfos, userDepartments);
			log.info("<---------sync department end-------use time ms---->" + (System.currentTimeMillis() - start));
		} catch (Exception e) {
			e.printStackTrace();
			log.error("sync user exception:", e);
		}
	}

	private void process(List<DepartmentInfo> departmentInfos, List<UserInfo> userNewInfos,
			List<UserDepartment> userDepartments) {
		if (departmentInfos != null && departmentInfos.size() > 0) {
			log.info("sync department size is " + departmentInfos.size());
			// 先处理根节点
			DepartmentInfo otherRoot = newOtherRoot();
			// 生成树形结构的
			genTree(departmentInfos, otherRoot);
			JPAQuery<Tuple> query = new JPAQuery<Tuple>(em);
			query.from(qDepartment).where(qDepartment.type.eq(Type.GROUP).and(qDepartment.parent.id.isNull()));
			Department root = (Department) query.fetch().get(0);
			/* Department root = departmentRepository.find; */
			// 开始同步
			syncInfo(otherRoot, root, userNewInfos, userDepartments);
		}
	}

	private DepartmentInfo newOtherRoot() {
		DepartmentInfo info = new DepartmentInfo();
		info.setDEPT_ID("root");
		info.setDEPT_NAME("四川省环境保护厅");
		return info;
	}

	private void syncInfo(DepartmentInfo other, Department myRoot, List<UserInfo> userNewInfos,
			List<UserDepartment> userDepartments) {
		// DepartmentDto temp = getDefault(other, myRoot);
		// 保存或者更新
		Department my = getDefault(other, myRoot);
		// 查找部门下的用户
		List<UserInfo> users = getUsers(userNewInfos, userDepartments, other.getDEPT_ID());
		// 保存用户
		saveUsers(users, my);

		if (other.getChildren() != null && other.getChildren().size() > 0) {
			for (DepartmentInfo info : other.getChildren()) {
				syncInfo(info, my, userNewInfos, userDepartments);
			}
		}
	}

	private void saveUsers(List<UserInfo> users, Department my) {
		if (users.size() == 0) {
			return;
		}
		List<List<DepartmentShortDto>> lists = new ArrayList<>();
		List<DepartmentShortDto> list = new ArrayList<>();
		lists.add(list);

		DepartmentShortDto shortDto = new DepartmentShortDto();
		shortDto.setFullname(my.getFullname());
		shortDto.setId(my.getId());
		shortDto.setShortname(my.getShortname());
		list.add(shortDto);
		for (UserInfo info : users) {
			UserDto user = getUserByLoginName(info.getUSER_NAME());
			if (user == null) {
				// 新增
				user = getDefaultUser(info, list);
				userService.save(user);
			} else {
				// 更新
				user.setEmail(info.getLOGIN_NAME());
				user.setDepartments(lists);
				userService.update(user.getId(), user);
			}
		}

	}

	private UserDto getDefaultUser(UserInfo info, List<DepartmentShortDto> departmentDtos) {
		List<List<DepartmentShortDto>> lists = new ArrayList<>();
		lists.add(departmentDtos);
		UserDto user = new UserDto();
		user.setUsername(info.getUSER_NAME());
		user.setFullname(info.getUSER_NAME());
		user.setEmail(info.getLOGIN_NAME());
		user.setPassword("123456");
		user.setMobile(info.getPHONE());
		// 默认不可用
		user.setEnabled(false);
		// 部门
		user.setDepartments(lists);
		// 角色
		BooleanBuilder builder = new BooleanBuilder();
		builder.and(QRole.role.name.eq("默认角色"));
		Optional<Role> Orole = roleRepositoryl.findOne(builder);
		List<RoleDto> roleDtos = new ArrayList<>();
		if (Orole.isPresent()) {
			RoleDto roleDto = new RoleDto();
			roleDto.setId(Orole.get().getId());
			roleDtos.add(roleDto);
		}
		user.setRoles(roleDtos);
		return user;
	}

	private UserDto getUserByLoginName(String name) {
		Optional<User> user = userRepository.findOneByUsernameIgnoreCase(name);
		if (user.isPresent()) {
			return userConverter.toDto(user);
		}
		return null;
	}

	private List<UserInfo> getUsers(List<UserInfo> allUsers, List<UserDepartment> userDepartments, String deptId) {
		List<UserInfo> list = new ArrayList<UserInfo>();
		for (UserDepartment userDepartment : userDepartments) {
			if (deptId.equals(userDepartment.getDEPT_ID())) {
				for (UserInfo newInfo : allUsers) {
					if (userDepartment.getUSER_ID().equals(newInfo.getUSER_ID())) {
						list.add(newInfo);
					}
				}
			}
		}

		return list;
	}

	private void genTree(List<DepartmentInfo> departmentInfos, DepartmentInfo root) {
		List<DepartmentInfo> children = findDepartByParentId(departmentInfos, root.getDEPT_ID());
		if (children != null && children.size() > 0) {
			root.setChildren(children);
			for (DepartmentInfo info : children) {
				genTree(departmentInfos, info);
			}
		}
	}

	private List<DepartmentInfo> findDepartByParentId(List<DepartmentInfo> departmentInfos, String parentId) {
		List<DepartmentInfo> list = new ArrayList<DepartmentInfo>();
		for (DepartmentInfo info : departmentInfos) {
			if (parentId.equals(info.getPARENT())) {
				list.add(info);
			}
		}
		return list;
	}

	private Department getDefault(DepartmentInfo other, Department myRoot) {
		// 首先判断数据库中是否存在
		DepartmentDto dto;
		Department temp;
		Department d = getDepartmentByTitleAndParentId(other.getDEPT_NAME(), myRoot.getId());
		if (d == null) {
			List<DepartmentShortDto> depts = new ArrayList<>();
			DepartmentShortDto dept = new DepartmentShortDto();
			dept.setId(myRoot.getId());
			depts.add(dept);
			// 新增
			dto = new DepartmentDto();
			dto.setFullname(other.getDEPT_NAME());
			dto.setShortname(other.getDEPT_NAME());
			dto.setState(Department.Status.ENABLED);
			dto.setParent(departmentConverter.toDto(myRoot));
			Long orderLong = getDepartmentMaxOrder(myRoot);
			if (orderLong == null) {
				orderLong = 0L;
			}
			dto.setOrder(orderLong + 1);
			dto.setType(Department.Type.DEPARTMENT);
			temp = departmentService.save(dto);
		} else {

			dto = departmentConverter.toDto(d);
			// 只更新这些
			dto.setFullname(other.getDEPT_NAME());
			dto.setShortname(other.getDEPT_NAME());
			temp = departmentService.update(dto.getId(), dto);
		}

		return temp;
	}

	/**
	 * 获取 子部门下最大的order
	 *
	 * @param parent
	 * @return
	 */
	private Long getDepartmentMaxOrder(Department parent) {
		JPAQuery<Long> query = new JPAQuery<Long>(em);
		query.select(qDepartment.order.max());
		query.from(qDepartment);
		query.where(qDepartment.parent.id.eq(parent.getId()));
		return query.fetchOne();
	}

	private Department getDepartmentByTitleAndParentId(String name, long parentId) {
		BooleanBuilder builder = new BooleanBuilder();
		builder.and(qDepartment.fullname.eq(name));
		builder.and(qDepartment.parent.id.eq(parentId));
		List<Department> list = (List<Department>) departmentRepository.findAll(builder.getValue());
		if (CollectionUtils.isNotEmpty(list)) {
			return list.get(0);
		}
		return null;
	}
}
